Skip to content

fix(reconciler): reconcile Flyout for DropDownButton + SplitButton + ToggleSplitButton#385

Open
arcadiogarcia wants to merge 1 commit into
microsoft:mainfrom
arcadiogarcia:arcadiog/fix-reconciler-flyout-button-update
Open

fix(reconciler): reconcile Flyout for DropDownButton + SplitButton + ToggleSplitButton#385
arcadiogarcia wants to merge 1 commit into
microsoft:mainfrom
arcadiogarcia:arcadiog/fix-reconciler-flyout-button-update

Conversation

@arcadiogarcia
Copy link
Copy Markdown

Mount wrote .Flyout for all three controls, but Update never touched it,
so data-driven flyout content (e.g. a MenuFlyout whose Items list is
state-derived, or a ContentFlyoutElement whose subtree depends on state)
stayed frozen at mount-time across re-renders. A button whose flyout
transitioned to null across renders also kept the stale flyout attached.

UpdateDropDownButton, UpdateSplitButton, and UpdateToggleSplitButton now
call ApplyFlyoutAttachment for Flyout, mirroring the Mount-side wiring
and the universal AttachedFlyout / ContextFlyout path already taken by
ApplyModifiers. ApplyFlyoutAttachment reuses the realized FlyoutBase
(so an already-open flyout stays open), clear+repopulates
MenuFlyout.Items, or reconciles content inside a Flyout.Content child
via UpdateFlyoutInPlace. UpdateDropDownButton also gains an o parameter
(the dispatch tuple was previously discarding it) and all three now take
requestRerender. The X-to-null case is handled with an explicit
.Flyout = null branch so detached flyouts no longer linger.

Adds FlyoutReconcileFixtures with six selftests that mutate flyout
content / item count / subtree across re-renders and assert the
rendered flyout reflects the new value (and the realized FlyoutBase
instance is preserved), plus a clear-on-null selftest.

Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com

…ToggleSplitButton

Mount wrote .Flyout for all three controls, but Update never touched it,
so data-driven flyout content (e.g. a MenuFlyout whose Items list is
state-derived, or a ContentFlyoutElement whose subtree depends on state)
stayed frozen at mount-time across re-renders. A button whose flyout
transitioned to null across renders also kept the stale flyout attached.

UpdateDropDownButton, UpdateSplitButton, and UpdateToggleSplitButton now
call ApplyFlyoutAttachment for Flyout, mirroring the Mount-side wiring
and the universal AttachedFlyout / ContextFlyout path already taken by
ApplyModifiers. ApplyFlyoutAttachment reuses the realized FlyoutBase
(so an already-open flyout stays open), clear+repopulates
MenuFlyout.Items, or reconciles content inside a Flyout.Content child
via UpdateFlyoutInPlace. UpdateDropDownButton also gains an `o` parameter
(the dispatch tuple was previously discarding it) and all three now take
requestRerender. The X-to-null case is handled with an explicit
`.Flyout = null` branch so detached flyouts no longer linger.

Adds FlyoutReconcileFixtures with six selftests that mutate flyout
content / item count / subtree across re-renders and assert the
rendered flyout reflects the new value (and the realized FlyoutBase
instance is preserved), plus a clear-on-null selftest.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a reconciliation gap in Reactor’s WinUI reconciler so .Flyout on DropDownButton, SplitButton, and ToggleSplitButton is updated across re-renders (instead of being “mount-only”), and adds selftest coverage to prevent regressions.

Changes:

  • Update UpdateDropDownButton, UpdateSplitButton, and UpdateToggleSplitButton to thread old + requestRerender and reconcile .Flyout via ApplyFlyoutAttachment, including X→null clearing.
  • Add FlyoutReconcileFixtures selftests to validate flyout content/items update across re-renders and flyout instances are preserved.
  • Register the new fixtures in SelfTestFixtureRegistry and document the fix in CHANGELOG.md.
Show a summary per file
File Description
tests/Reactor.AppTests.Host/SelfTest/SelfTestFixtureRegistry.cs Registers the new flyout reconciliation selftests in the selftest registry.
tests/Reactor.AppTests.Host/SelfTest/Fixtures/FlyoutReconcileFixtures.cs Adds new fixtures covering flyout text/content/items updates and X→null flyout clearing.
src/Reactor/Core/Reconciler.Update.cs Updates button reconciler paths to reconcile .Flyout during Update (not just Mount).
CHANGELOG.md Documents the reconciler fix and the added regression tests.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 4

Comment on lines +743 to +746
if (n.Flyout is not null)
ApplyFlyoutAttachment(ddb, o.Flyout, n.Flyout, requestRerender);
else if (o.Flyout is not null)
ddb.Flyout = null;
Comment on lines +756 to +759
if (n.Flyout is not null)
ApplyFlyoutAttachment(sb, o.Flyout, n.Flyout, requestRerender);
else if (o.Flyout is not null)
sb.Flyout = null;
Comment on lines +780 to +783
if (n.Flyout is not null)
ApplyFlyoutAttachment(tsb, o.Flyout, n.Flyout, requestRerender);
else if (o.Flyout is not null)
tsb.Flyout = null;
Comment on lines +1 to +8
using Microsoft.UI.Reactor.AppTests.Host.SelfTest;
using Microsoft.UI.Reactor.Core;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using static Microsoft.UI.Reactor.Factories;
using WinPrim = Microsoft.UI.Xaml.Controls.Primitives;
using WinUI = Microsoft.UI.Xaml.Controls;

Copy link
Copy Markdown
Collaborator

@codemonkeychris codemonkeychris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address the CR feedback from AIs, i ran 3 different robot code reviews against this, and did a human spot check, the combined feedback is all inline. just have your robot action this, and then you are clear to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants